home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 001-025 / disk_002 / cc / cc.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  22KB  |  781 lines

  1. /************************************************************************
  2.  *                                    *
  3.  *            Copyright (c) 1985, Fred Fish            *
  4.  *                All Rights Reserved                *
  5.  *                                    *
  6.  *    This software and/or documentation is released into the        *
  7.  *    public domain for personal, non-commercial use only.        *
  8.  *    Limited rights to use, modify, and redistribute are hereby    *
  9.  *    granted for non-commercial purposes, provided that all        *
  10.  *    copyright notices remain intact and all changes are clearly    *
  11.  *    documented.  The author makes no warranty of any kind with    *
  12.  *    respect to this product and explicitly disclaims any implied    *
  13.  *    warranties of merchantability or fitness for any particular    *
  14.  *    purpose.                            *
  15.  *                                    *
  16.  ************************************************************************
  17.  */
  18.  
  19.  
  20. /*
  21.  *    cc -- C compiler front end for Amiga and Lattice C.
  22.  *
  23.  *    Somewhat AMIGA/Lattice dependent, but can probably be adapted to
  24.  *    other systems with a minimum of work.  I have attempted to keep
  25.  *    portability in mind as much as possible.
  26.  *
  27.  */
  28.  
  29. char _sccsid[] = "@(#)cc.c    1.8";
  30.  
  31. #include <stdio.h>
  32.  
  33. /*
  34.  *    The following allow use on systems that don't have my macro based
  35.  *    debugging package.  The default, for now, is to assume it is not
  36.  *    available.
  37.  */
  38.  
  39. #ifdef DBUG
  40. #  include <local/dbug.h>
  41. #else    /* !DBUG */
  42. #  define DBUG_ENTER(a)
  43. #  define DBUG_RETURN(a) return(a)
  44. #  define DBUG_VOID_RETURN return
  45. #  define DBUG_2(a,b)
  46. #  define DBUG_3(a,b,c)
  47. #  define DBUG_4(a,b,c,d)
  48. #  define DBUG_5(a,b,c,d,e)
  49. #  define DBUG_PUSH(a)
  50. #endif    /* DBUG */
  51.  
  52. /*
  53.  *    IMPLEMENTATION NOTES
  54.  *
  55.  *    Some of the builtin (artificial) limits could be removed by
  56.  *    using dynamically allocated data structures, such as keeping the
  57.  *    operand list as a linked list with space for each link supplied
  58.  *    by malloc.  This would certainly increase the code space, while
  59.  *    reducing the statically allocated data space.  The net result
  60.  *    would probably be a program requiring about the same amount of
  61.  *    total memory for most day to day usages.  When source is not
  62.  *    available to the end user, maximum flexibility is a must and
  63.  *    dynamic allocation is the only way to go.  In this case however
  64.  *    it is not clear that the added complexity is worth it, since
  65.  *    source should be available for anyone wishing to expand the
  66.  *    limits.
  67.  *
  68.  *    One last note, if you are going to have builtin limits then
  69.  *    check the @#$%&* things for overflow.  Running off the end of
  70.  *    an array with no indication that something is wrong, other
  71.  *    than a crash, if definitely unfriendly!
  72.  *
  73.  */
  74.  
  75.  
  76. /*
  77.  *    Manifest constants which can be tuned to fit requirements.
  78.  */
  79.  
  80. #define CMDBUFFERSIZE (1024)    /* Size of command buffer for CLI command */
  81. #define MAXOPERANDS (64)    /* Maximum number of operands on cmd line */
  82. #define MAXDEFINES (32)        /* Maximum number of -D<name> args */
  83. #define MAXUNDEFINES (32)    /* Maximum number of -U<name> args */
  84. #define MAXINCDIRS (16)        /* Maximum number of -I<filename> args */
  85. #define MAXLIBS (16)        /* Maximum number of -l<lib> args */
  86. #define ARGSIZE (64)        /* Size of temp args for cmd line */
  87.  
  88. /*
  89.  *    Define QUADDEV to be the default place where you want the compiler
  90.  *    intermediate files (quad files) to be created.  For systems with
  91.  *    512K or more, the preferred place is the ram disk.  However,
  92.  *    really big compiles may need to be done on a hard disk.
  93.  *    In either case, the default can be overridden with the -q option.
  94.  */
  95.  
  96. #define QUADDEV    "ram:"        /* Keep intermediate files in ram */
  97. /* #define QUADDEV "" */    /* Keep intermediate files in current dir */
  98.  
  99. /*
  100.  *    Manifest constants which are generally the same on all systems.
  101.  */
  102.  
  103. #define EOS '\000'        /* End of string character */
  104.  
  105. /*
  106.  *    Command line arguments that represent files to be compiled, assembled,
  107.  *    or linked, are kept track of via an "Operand" array.  If, for example,
  108.  *    the file name is "df0:mydir/junk.c", then the Rootname is
  109.  *    "df0:mydir/junk", the Basename is "junk", and the Suffix is "c".
  110.  *    String suffixes are used, rather than single character suffixes, to
  111.  *    allow use of names with multicharacter suffixes.
  112.  */
  113.  
  114. struct Operand {        /* Info about each operand (non option) */
  115.     char *Rootname;        /* Name minus any suffix */
  116.     char *Basename;        /* Name minus any prefix or suffix */
  117.     char *Suffix;        /* Suffix of operand */
  118. };
  119.  
  120. static struct Operand Operands[MAXOPERANDS];    /* Table of operands */
  121. static int NOperands = 0;            /* Number of operands found */
  122. static char *Defines[MAXDEFINES];        /* Table of defines */
  123. static int NDefines = 0;            /* Number of defines */
  124. static char *UnDefines[MAXUNDEFINES];        /* Table of undefines */
  125. static int NUnDefines = 0;            /* Number of undefines */
  126. static char *UserInc[MAXINCDIRS];        /* Table of include dirs */
  127. static int NUserInc = 0;            /* Number of include dirs */
  128. static char *Libs[MAXLIBS];            /* Table of library args */
  129. static int NLibs = 0;                /* Number of library args */
  130.  
  131. /*
  132.  *    The command line buffer for child commands is allocated statically,
  133.  *    rather than as an automatic, to forstall problems with stack limits
  134.  *    in initial implementations.  Hopefully, automatic stack growth will
  135.  *    be implemented in future release of the C compiler.  If nothing
  136.  *    else, someday I will read the manuals and figure out how to explicitly
  137.  *    grow the stack...
  138.  *
  139.  */
  140.  
  141. static char Command[CMDBUFFERSIZE];        /* Command line buffer */
  142. static char *EndCommand = Command;        /* End of current command */
  143.  
  144. /*
  145.  *    Macros to determine the suffix type of a file given a pointer to
  146.  *    its operand structure.
  147.  */
  148.  
  149. #define CFILE(op) (strcmp(op->Suffix,"c")==0)
  150. #define SFILE(op) (strcmp(op->Suffix,"s")==0)
  151. #define OFILE(op) (strcmp(op->Suffix,"o")==0)
  152. extern int strcmp ();
  153.  
  154. /*
  155.  *    Now some macros to map from unix names to the AMIGA equivalents,
  156.  *    and to enable abort on control-C.
  157.  */
  158.  
  159. #ifdef AMIGA
  160. #  define system(a) (Execute(a,0,0))
  161. #  define ENABLE_ABORT (Enable_Abort = 1)
  162. #  define DISABLE_ABORT (Enable_Abort = 0)
  163. #  define CHECK_ABORT Check_Abort()
  164.    extern int Enable_Abort;            /* Enable abort on CNTL-C */
  165.    static void Check_Abort ();        /* Test for abort requested */
  166. #else
  167. #  define ENABLE_ABORT                /* Null expansion */
  168. #  define DISABLE_ABORT                /* Null expansion */
  169. #  define CHECK_ABORT                /* Null expansion */
  170. #endif    /* AMIGA */
  171.  
  172. /*
  173.  *    Set list of places to search for various executables, libraries, etc.
  174.  *    Searched in order, first match wins, null string is current directory.
  175.  *    Note that these names are used as prefixes exactly as given, so
  176.  *    device names must end in ':' and directory names must end in '/'.
  177.  *
  178.  */
  179.  
  180. static char *Devices[] = {
  181.     "",
  182.     "ram:",
  183.     "df0:",
  184.     "df1:",
  185.     NULL
  186. };
  187.  
  188. static char *BinDirs[] = {
  189.     "",
  190.     "ram:c/",
  191.     "df0:c/",
  192.     "df1:c/",
  193.     NULL
  194. };
  195.  
  196. static char *LibDirs[] = {
  197.     "",
  198.     "ram:lib/",
  199.     "df0:lib/",
  200.     "df1:lib/",
  201.     NULL
  202. };
  203.  
  204. static char *IncDirs[] = {
  205.     "ram:include/",
  206.     "df0:include/",
  207.     "df1:include/",
  208.     NULL
  209. };
  210.  
  211. /*
  212.  *    Flags set by command line arguments/
  213.  */
  214.  
  215. static int cflag;            /* -c flag given */
  216. static int Pflag;            /* -P flag given */
  217. static int Sflag;            /* -S flag given */
  218. static int Vflag;            /* -V flag given (non-standard) */
  219.  
  220. static int ErrCount = 0;        /* Count of compile/assemble errors */
  221. static char *outfile = "a.out";        /* Output file name from linker */
  222. static char *QuadDev = QUADDEV;        /* Where to keep quad files */
  223.  
  224. static char *Locate ();            /* Find a file */
  225. static void AddToCommand ();        /* Add argument to command buffer */
  226. static void InitCommand ();        /* Initialize command buffer */
  227. static void Fatal ();            /* Quit with fatal error */
  228. static void Warning ();            /* Issue warning message */
  229. static void AddOperandToList ();    /* Add .c, .s, or .o file to list */
  230. static void CleanObjects ();        /* Remove .o for link and go mode */
  231. static void MakeObjects ();        /* Reduce to list of object files */
  232. static void ParseCommandLine ();    /* Deal with command line */
  233. static void Compile ();            /* Translate from .c to .o */
  234. static void Assemble ();        /* Translate from .s to .o */
  235. static void Link ();            /* Gather .o's into executable */
  236.  
  237. extern void exit ();            /* See exit(2) */
  238.  
  239. /*
  240.  *    Main entry point.  Note that despite common usage where main is
  241.  *    essentially of type void, we declare it explicitly to return
  242.  *    an int, and actually return a value.  In most implementations,
  243.  *    the value returned from main is the exit status of the program.
  244.  *    Whether this applies to Lattice C or not, I'm not sure yet.
  245.  */
  246.  
  247. int main (argc, argv)
  248. int argc;
  249. char *argv[];
  250. {
  251.     DBUG_ENTER ("main");
  252.     ENABLE_ABORT;
  253.     ParseCommandLine (argc, argv);
  254.     MakeObjects ();
  255.     if (!cflag && !Pflag && !Sflag && ErrCount == 0) {
  256.     Link ();
  257.     CleanObjects ();
  258.     }
  259.     DBUG_RETURN (0);
  260. }
  261.  
  262. /*
  263.  *    The following macro is used to allow optional whitespace between
  264.  *    an option and it's argument.  Argp is left pointing at the option
  265.  *    and argv and argc are adjusted accordingly if necessary.
  266.  *
  267.  *    Note that there is no check for missing option arguments.  In
  268.  *    particular, -o -V will blindly take -V as the output file name.
  269.  *
  270.  */
  271.  
  272. #define XARG(argc,argv,argp) {if(*++argp==EOS){argp=(*argv++);argc--;}}
  273.  
  274. static void ParseCommandLine (argc, argv)
  275. int argc;
  276. char **argv;
  277. {
  278.     register char *argp;    
  279.  
  280.     DBUG_ENTER ("ParseCommandLine");
  281.     argc--;
  282.     argv++;
  283.     while (argc-- > 0) {
  284.     CHECK_ABORT;
  285.     argp = *argv++;
  286.     if (*argp != '-') {
  287.         AddOperandToList (argp);
  288.     } else {
  289.         switch (*++argp) {
  290.         case '#':
  291.             XARG (argc, argv, argp);
  292.             DBUG_PUSH (argp);
  293.             break;
  294.         case 'c':
  295.             cflag++;
  296.             break;
  297.         case 'D':
  298.             XARG (argc, argv, argp);
  299.             if (NDefines >= MAXDEFINES) {
  300.             Fatal ("too many -D args (%d max)", MAXDEFINES);
  301.             }
  302.             Defines[NDefines++] = argp;
  303.             break;
  304.         case 'E':
  305.             Warning ("-E unimplemented, converted to -P instead");
  306.             Pflag++;
  307.             break;
  308.         case 'f':
  309.             break;    /* NOP for now, just eat it */
  310.         case 'g':
  311.             break;    /* NOP for now, just eat it */
  312.         case 'I':
  313.             XARG (argc, argv, argp);
  314.             if (NUserInc >= MAXINCDIRS) {
  315.             Fatal ("too many -I args (%d max)", MAXINCDIRS);
  316.             }
  317.             UserInc[NUserInc++] = argp;
  318.             break;
  319.         case 'l':
  320.             XARG (argc, argv, argp);
  321.             if (NLibs > MAXLIBS) {
  322.             Fatal ("too many -l args (%d max)", MAXLIBS);
  323.             }
  324.             Libs[NLibs++] = argp;
  325.             break;
  326.         case 'O':
  327.             break;    /* NOP for now, just eat it */
  328.         case 'o':
  329.             XARG (argc, argv, argp);
  330.             outfile = argp;
  331.             break;
  332.         case 'P':
  333.             Pflag++;
  334.             break;
  335.         case 'q':        /* Warning, non-standard */
  336.             XARG (argc, argv, argp);
  337.             QuadDev = argp;
  338.             break;
  339.         case 'S':
  340.             Sflag++;
  341.             Warning ("-S option not yet implemented, ignored");
  342.             break;
  343.         case 's':
  344.             break;        /* NOP for now, just eat it */
  345.         case 'U':
  346.             XARG (argc, argv, argp);
  347.             if (NUnDefines >= MAXUNDEFINES) {
  348.             Fatal ("too many -U args (%d max)", MAXUNDEFINES);
  349.             }
  350.             UnDefines[NUnDefines++] = argp;
  351.             break;
  352.         case 'V':
  353.             Vflag++;
  354.             break;
  355.         default:
  356.             Warning ("unknown option '%c'", (char *) *argp);
  357.             break;
  358.         }
  359.     }
  360.     }
  361.     DBUG_VOID_RETURN;
  362. }
  363.  
  364. /*
  365.  *    For each operand, do compilation or assembly as necessary, to
  366.  *    reduce to an object file in the current directory.
  367.  */
  368.  
  369. static void MakeObjects ()
  370. {
  371.     register int index;
  372.     register struct Operand *op;
  373.  
  374.     DBUG_ENTER ("MakeObjects");
  375.     for (index = 0; index < NOperands; index++) {
  376.     CHECK_ABORT;
  377.     op = &Operands[index];
  378.     if (NOperands > 1 && (CFILE (op) || SFILE (op))) {
  379.         printf ("%s.%s:\n", op -> Rootname, op -> Suffix);
  380.     }
  381.     if (CFILE (op)) {
  382.         Compile (op);
  383.     } else if (SFILE (op)) {
  384.         Assemble (op);
  385.     }
  386.     }
  387.     DBUG_VOID_RETURN;
  388. }
  389.  
  390. /*
  391.  *    Note that commands to cc of the form "-l<name>" get interpreted
  392.  *    to mean use a library called "name.lib" from the library
  393.  *    directory.
  394.  */
  395.  
  396. static void Link ()
  397. {
  398.     register int index;
  399.     register struct Operand *op;
  400.     register char *name;
  401.     auto char buffer[ARGSIZE];
  402.     
  403.     DBUG_ENTER ("Link");
  404.     InitCommand ();
  405.     AddToCommand ("%s ", Locate ("alink", BinDirs));
  406.     AddToCommand ("%s", Locate ("Lstartup.obj", LibDirs));
  407.     for (index = 0; index < NOperands; index++) {
  408.     op = &Operands[index];
  409.     if (OFILE (op)) {
  410.         name = op -> Rootname;
  411.     } else {
  412.         name = op -> Basename;
  413.     }
  414.     AddToCommand ("+%s.o", name);
  415.     }
  416.     AddToCommand ("%s", " library ");
  417.     for (index = 0; index < NLibs; index++) {
  418.     sprintf (buffer, "%s.lib", Libs[index]);
  419.     AddToCommand ("%s+", Locate (buffer, LibDirs));
  420.     }
  421.     AddToCommand ("%s+", Locate ("lc.lib", LibDirs));
  422.     AddToCommand ("%s", Locate ("amiga.lib", LibDirs));
  423.     AddToCommand (" to %s map nil:", outfile);
  424.     (void) RunCommand ();
  425.     DBUG_VOID_RETURN;
  426. }
  427.  
  428. /*VARARGS1*/
  429. static void Warning (fmt, arg1, arg2, arg3)
  430. char *fmt;
  431. char *arg1;
  432. char *arg2;
  433. char *arg3;
  434. {
  435.     fprintf (stderr, "cc -- warning: ");
  436.     fprintf (stderr, fmt, arg1, arg2, arg3);
  437.     fprintf (stderr, "\n");
  438.     (void) fflush (stderr);
  439. }
  440.  
  441. /*VARARGS1*/
  442. static void Fatal (fmt, arg1, arg2, arg3)
  443. char *fmt;
  444. char *arg1;
  445. char *arg2;
  446. char *arg3;
  447. {
  448.     fprintf (stderr, "cc -- fatal error: ");
  449.     fprintf (stderr, fmt, arg1, arg2, arg3);
  450.     fprintf (stderr, "\n");
  451.     (void) fflush (stderr);
  452.     exit (1);
  453. }
  454.  
  455. /*
  456.  *    Split an operand name into rootname, basename, and suffix
  457.  *    components.  The rootname is the full name, minus any suffix,
  458.  *    but including any prefix.  The basename is the rootname minus
  459.  *    any prefix.  The suffix is anything after the last '.' character.
  460.  *    Only the suffix is allowed to be the null string.
  461.  */
  462.  
  463. static void AddOperandToList (filename)
  464. char *filename;
  465. {
  466.     register char *split;
  467.     register struct Operand *op;
  468.     extern char *strrchr ();
  469.  
  470.     DBUG_ENTER ("AddOperandToList");
  471.     DBUG_3 ("ops", "add file '%s' to operand list", filename);
  472.     if (NOperands >= MAXOPERANDS) {
  473.     Fatal ("too many files (%d max)\n", MAXOPERANDS);
  474.     }
  475.     op = &Operands[NOperands];
  476.     op -> Rootname = filename;
  477.     if ((split = strrchr (filename, '/')) == NULL) {
  478.     split = strrchr (filename, ':');
  479.     }
  480.     if (split == NULL) {
  481.     op -> Basename = filename;
  482.     } else {
  483.     op -> Basename = ++split;
  484.     }
  485.     if ((split = strrchr (filename, '.')) == NULL) {
  486.     op -> Suffix = "";
  487.     } else {
  488.     *split++ = EOS;
  489.     op -> Suffix = split;
  490.     }
  491.     DBUG_3 ("ops", "rootname '%s'", op -> Rootname);
  492.     DBUG_3 ("ops", "basename '%s'", op -> Basename);
  493.     DBUG_3 ("ops", "suffix '%s'", op -> Suffix);
  494.     NOperands++;
  495.     DBUG_VOID_RETURN;
  496. }
  497.  
  498. /*
  499.  *    Compile one operand from a C source program to an object module.
  500.  */
  501.  
  502. static void Compile (op)
  503. struct Operand *op;
  504. {
  505.     DBUG_ENTER ("Compile");
  506.     if (!Sflag && Pass1 (op) && !Pflag) {        /* Order important! */
  507.     CHECK_ABORT;
  508.     (void) Pass2 (op);
  509.     }
  510.     DBUG_VOID_RETURN;
  511. }
  512.  
  513. /*
  514.  *    Note that because of brain-damage in the fact that -p to lc1 removes
  515.  *    all predefined defs, we must add them so replacing -c with -P in the
  516.  *    cc command line will result in the same set of predefined symbols.
  517.  *    This is rather ugly and leaves a hole for future problems if we
  518.  *    get out of sync with respect to what names the compiler predefines.
  519.  */
  520.  
  521. static int Pass1 (op)
  522. register struct Operand *op;
  523. {
  524.     register int status;
  525.     register int index;
  526.     
  527.     DBUG_ENTER ("Pass1");
  528.     InitCommand ();
  529.     AddToCommand ("%s", Locate ("lc1", BinDirs));
  530.     if (Pflag) {
  531.     AddToCommand (" -o%s.i -p -DAMIGA -DM68000 -DSPTR", op -> Basename);
  532.     } else {
  533.     AddToCommand (" -o%s%s.q", QuadDev, op -> Basename);
  534.     }
  535.     for (index = 0; index <NUserInc; index++) {
  536.     AddToCommand (" -i%s/", UserInc[index]);
  537.     }
  538.     for (index = 0; index <NUnDefines; index++) {
  539.     /*************************
  540.     AddToCommand (" -u%s", UnDefines[index]);
  541.     **************************/
  542.     Warning ("-U%s ignored! (unimplemented)", UnDefines[index]);
  543.     }
  544.     for (index = 0; index <NDefines; index++) {
  545.     AddToCommand (" -d%s", Defines[index]);
  546.     }
  547.     AddToCommand (" -i%s/", Locate ("include", Devices));
  548.     AddToCommand (" -i%s/", Locate ("lattice", IncDirs));
  549.     AddToCommand (" %s", op -> Rootname);
  550.     status = RunCommand ();
  551.     DBUG_RETURN (status);
  552. }
  553.  
  554. /*
  555.  *    Run second pass of compiler on a single operand.
  556.  */
  557.  
  558. static int Pass2 (op)
  559. struct Operand *op;
  560. {
  561.     int status;
  562.     
  563.     DBUG_ENTER ("Pass2");
  564.     InitCommand ();
  565.     AddToCommand ("%s", Locate ("lc2", BinDirs));
  566.     AddToCommand (" -o%s.o", op -> Basename);
  567.     AddToCommand (" %s%s", QuadDev, op -> Basename);
  568.     status = RunCommand ();
  569.     DBUG_RETURN (status);
  570. }
  571.  
  572. /*
  573.  *    I have not yet had occasion to use the macro assembler, so this
  574.  *    part is not yet implemented.  If anyone wants to send me the
  575.  *    appropriate code, I will be glad to install it.
  576.  */
  577.  
  578. static void Assemble (op)
  579. struct Operand *op;
  580. {
  581.     DBUG_ENTER ("Assemble");
  582.     Warning ("assembly pass not yet implemented");
  583.     ErrCount++;
  584.     DBUG_VOID_RETURN;
  585. }
  586.  
  587. /*
  588.  *    As far as I can tell, the child status is not returned, only
  589.  *    whether or not the child could be run.  So, how do we find out
  590.  *    whether there was an error or not?  It's probably in the manuals
  591.  *    somewhere, I just haven't had time to dig yet.
  592.  *
  593.  *    Note that because Lattice printf is not capable of printing more
  594.  *    than 200 characters at a time, we must spit them out one at a time
  595.  *    to make sure the entire command line gets printed when -V is used.
  596.  *
  597.  */
  598.  
  599. static int RunCommand ()
  600. {
  601.     int status;
  602.     register char *cmdp;
  603.     
  604.     DBUG_ENTER ("RunCommand");
  605.     DBUG_3 ("cmd", "execute '%s'", Command);
  606.     if (Vflag) {
  607.     for (cmdp = Command; *cmdp != '\000'; cmdp++) {
  608.         putchar (*cmdp);                /* see above */
  609.     }
  610.     putchar ('\n');
  611.     (void) fflush (stdout);
  612.     }
  613.     CHECK_ABORT;
  614.     status = system (Command);
  615.     DBUG_3 ("sys", "subcommand returns status %d", status);
  616.     if (!status) {
  617.     ErrCount++;
  618.     }
  619.     DBUG_RETURN (status);
  620. }
  621.  
  622. /*
  623.  *    Look through the list of paths pointed to by "vec" until we find
  624.  *    a file with name given pointed to by "namep".  If none is found,
  625.  *    the name pointed to by namep is returned.
  626.  */
  627.  
  628. static char *Locate (namep, vec)
  629. char *namep;
  630. char **vec;
  631. {
  632.     static char namebuf[ARGSIZE];
  633.     
  634.     DBUG_ENTER ("Locate");
  635.     while (*vec != NULL) {
  636.     (void) sprintf (namebuf, "%s%s", *vec, namep);
  637.     DBUG_3 ("try", "look for '%s'", namebuf);
  638.     if (Readable (namebuf)) {
  639.         namep = namebuf;
  640.         break;
  641.     }
  642.     vec++;
  643.     }
  644.     DBUG_RETURN (namep);
  645. }
  646.  
  647. /*
  648.  *    Check to see if the file exists and is readable.
  649.  */
  650.  
  651. #ifdef unix
  652. #  include <fcntl.h>
  653. #else
  654. #  include <libraries/dos.h>
  655. #endif
  656.  
  657. static int Readable (name)
  658. char *name;
  659. {
  660.     register int status = 0;
  661.     register int fildes;
  662.     
  663.     DBUG_ENTER ("Readable");
  664. #ifdef unix
  665.     fildes = open (name, O_RDONLY);
  666.     if (fildes >= 0) {
  667.     (void) close (fildes);
  668.     status = 1;
  669.     }
  670. #else
  671.     fildes = Lock (name, ACCESS_READ);
  672.     if (fildes != 0) {
  673.         UnLock (fildes);
  674.     status = 1;
  675.     }
  676. #endif
  677.     DBUG_RETURN (status);
  678. }
  679.  
  680. /*
  681.  *    Do explicit check for abort.  When Enable_Abort is non-zero,
  682.  *    Chk_Abort() cause program termination if CNTRL-C or CNTRL-D has
  683.  *    been received.  Thus, we temporarily set it back to zero while we
  684.  *    do the explicit test, so we can do our own clean up and exit.
  685.  *    Note that if the -V flag was used, we spit out a confirming message
  686.  *    that we are quitting.
  687.  *
  688.  *    Since we previously set Check_Abort to non-zero, this routine may be
  689.  *    overkill.
  690.  */
  691.  
  692. #ifdef AMIGA
  693. static void Check_Abort ()
  694. {
  695.     extern int Chk_Abort ();
  696.     
  697.     DBUG_ENTER ("Check_Abort");
  698.     DBUG_2 ("abort", "do explicit test for CNTRL-C");
  699.     DISABLE_ABORT;
  700.     if (Chk_Abort () != 0) {
  701.     if (Vflag) {
  702.         printf ("cc - terminated by request\n");
  703.     }
  704.     exit (1);
  705.     }
  706.     ENABLE_ABORT;
  707.     DBUG_VOID_RETURN;
  708. }
  709. #endif
  710.  
  711. /*
  712.  *    Initialize the command line buffer and associated variables to
  713.  *    discard any previous command line.
  714.  */
  715.  
  716. static void InitCommand ()
  717. {
  718.     Command[0] = '\000';
  719.     EndCommand = Command;
  720. }
  721.  
  722. /*
  723.  *    Build string to add to end of current command line, checking
  724.  *    for overflow in the command buffer and maintaining the pointer
  725.  *    to the end of the current command.
  726.  *
  727.  *    Note that we are a "printf type" of command, and can be called
  728.  *    with up to three "char *" arguments.  There is a portability
  729.  *    problem here, but Lattice hasn't yet made "varargs" a standard
  730.  *    part of their distribution.
  731.  *
  732.  *    Also, note that the return argument of sprintf is supposed to be
  733.  *    the number of characters to be added to the buffer.  This is
  734.  *    not always true for some C implementations.  In particular,
  735.  *    sprintf in BSD4.1 returns a pointer.  Thus we don't use the
  736.  *    return argument.
  737.  *
  738.  */
  739.  
  740. /*VARARGS1*/
  741. static void AddToCommand (fmt, arg1, arg2, arg3)
  742. char *fmt;
  743. char *arg1, *arg2, *arg3;
  744. {
  745.     register int length;
  746.     auto char buffer[ARGSIZE];
  747.  
  748.     (void) sprintf (buffer, fmt, arg1, arg2, arg3);
  749.     length = strlen (buffer);
  750.     if ((EndCommand - Command) + length >= sizeof (Command)) {
  751.     Fatal ("command line too long (%d char max)", sizeof (Command));
  752.     } else {
  753.     (void) strcat (EndCommand, buffer);
  754.     EndCommand += length;
  755.     }
  756. }
  757.  
  758. /*
  759.  *    If an executable is made from a single C file, the normal behavior
  760.  *    for the unix environment is to treat the .o file as an intermediate
  761.  *    file and remove it, so we follow suit.
  762.  */
  763.  
  764. static void CleanObjects ()
  765. {
  766.     auto char buffer[ARGSIZE];
  767.     register struct Operand *op;
  768.     
  769.     DBUG_ENTER ("CleanObjects");
  770.     if (NOperands == 1) {
  771.     op = &Operands[0];
  772.     if (CFILE (op) || SFILE (op)) {
  773.         sprintf (buffer, "%s.o", op -> Basename);
  774.         if (!DeleteFile (buffer)) {
  775.         Warning ("can't delete '%s'", buffer);
  776.         }
  777.     }
  778.     }
  779.     DBUG_VOID_RETURN;
  780. }
  781.